#include "ae.h"
#include <time.h>
#include <sys/select.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>


int ae_create()
{
    return epoll_create(1);
}

int ae_free(int aefd)
{
    return close(aefd);
}

int ae_add_read(int aefd,int fd)
{
    struct epoll_event e;
    e.events = EPOLLIN;
    e.data.fd = fd;
    //printf("ae_add_read call: aefd=%d,fd=%d.\n",aefd,fd);
    return epoll_ctl(aefd,EPOLL_CTL_ADD,fd,&e)!=-1;
}

int ae_add_write(int aefd,int fd)
{
    struct epoll_event e;
    e.events = EPOLLOUT|EPOLLET;
    e.data.fd = fd;
    return epoll_ctl(aefd,EPOLL_CTL_ADD,fd,&e)!=-1;
}

int ae_del_event(int aefd,int fd)
{
    return epoll_ctl(aefd,EPOLL_CTL_DEL,fd,NULL)!=-1;
}

int ae_enable_event(int aefd,int fd,bool readable,bool writable)
{
    struct epoll_event e;
    e.events = (readable?EPOLLIN:0)|(writable?EPOLLOUT:0);
    e.data.fd = fd;
    //printf("ae_enable_event call: aefd=%d,fd=%d,readable=%d,writable=%d.\n",aefd,fd,readable,writable);
    return epoll_ctl(aefd,EPOLL_CTL_MOD,fd,&e)!=-1;
}

//int ae_poll(int aefd,event_t* fired,int nfired,int timeout)
//{
//    struct epoll_event events[AE_MAXEVENT];
//    int n = epoll_wait(aefd,events,AE_MAXEVENT,timeout);
//    int i=0;
//    for(;i<n && i<nfired;i++)
//    {
//        struct epoll_event* e = events+i;
//        fired[i].fd = e->data.fd;
//        int mask = e->events;
//        if(mask&(EPOLLERR|EPOLLHUP))
//            mask |= (EPOLLIN|EPOLLOUT);
//        fired[i].read = (mask&EPOLLIN)!=0;
//        fired[i].write = (mask&EPOLLOUT)!=0;
//        //printf("ae_poll get a event: fd=%d,read=%d,write=%d\n",fired[i].fd,fired[i].read,fired[i].write);
//    }
//    return i;
//}

int ae_poll2(int aefd, int timeout, int(*func)(void*,int, int, int, bool, bool, int), void* usrdata, int usrhandle)
{
    struct epoll_event events[AE_MAXEVENT];
    int n = epoll_wait(aefd,events,AE_MAXEVENT,timeout);
    int i=0;
    for(;i<n;i++)
    {
        struct epoll_event* e = events+i;
        int fd = e->data.fd;
        int mask = e->events;
        if(mask&(EPOLLERR|EPOLLHUP))
            mask |= (EPOLLIN|EPOLLOUT);
        bool read = (mask&EPOLLIN)!=0;
        bool write = (mask&EPOLLOUT)!=0;
        //printf("ae_poll get a event: fd=%d,read=%d,write=%d\n",fired[i].fd,fired[i].read,fired[i].write);
        func(usrdata,usrhandle,aefd,fd,read,write,e->events);
    }
    if(n<0)
    {
        if(errno != EINTR)
        {
            //printf("Error in %s(), accept: %s\n", __func__, strerror(errno));
            return -1;
        }
    }
    return 0;
}


int ae_wait(int fd,int mask,int timeoutMs)//if timeoutMs<0, wait forever or error occurs
{
    fd_set fdr, fdw;
    fd_set* fdr_ptr=NULL;
    fd_set* fdw_ptr=NULL;
    int retmask = 0,retval;
    if(mask&AE_READABLE)
    {
        FD_ZERO(&fdr);  
        FD_SET(fd, &fdr);
        fdr_ptr = &fdr;
    }
    if(mask&AE_WRITABLE){
        FD_ZERO(&fdw);
        FD_SET(fd, &fdw);
        fdw_ptr = &fdw;
    }
    struct timeval timeout;
    struct timeval* tim_ptr=NULL;
    if(timeoutMs>=0)
    {
        timeout.tv_sec = 0;
        timeout.tv_usec = timeoutMs*1000; 
        tim_ptr = &timeout;
    }
    if((retval=select(fd+1,fdr_ptr,fdw_ptr,NULL,tim_ptr))==1)
    {
        if(fdr_ptr!=NULL&&FD_ISSET(fd, fdr_ptr)) retmask |= AE_READABLE;
        if(fdw_ptr!=NULL&&FD_ISSET(fd, fdw_ptr)) retmask |= AE_WRITABLE;
        return retmask;
    }
    return 0;
}

